package io.github.lopssh.mybatis.auditlog.interceptor.handler;

import org.apache.commons.collections.map.CaseInsensitiveMap;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class DBMetaObjectHolder
{
    @SuppressWarnings("unchecked")
    private static final Map<String, String> primaryKeys = new CaseInsensitiveMap();

    @SuppressWarnings("unchecked")
    private static final Map<String, List<String>> tableColumns = new CaseInsensitiveMap();

    private static Boolean initialized = Boolean.FALSE;

    private static String retrievePrimaryKey(Connection connection, String table)
    {
        String primaryKey = null;
        try
        {
            ResultSet resultSet = connection.getMetaData().getPrimaryKeys(null, connection.getMetaData().getUserName(), table);
            if (resultSet.next())
                primaryKey = resultSet.getString("COLUMN_NAME");
            resultSet.close();
        } catch (SQLException e)
        {
            e.printStackTrace();
        }
        return primaryKey;
    }

    private static List<String> retrieveTableColumns(Connection connection, String table)
    {
        List<String> columns = null;
        if (!tableColumns.containsKey(table))
        {
            try
            {
                columns = new ArrayList<>();
                ResultSet resultSet = connection.getMetaData().getColumns(null, connection.getMetaData().getUserName(), table, "%");
                while (resultSet.next())
                {
                    String columnName = resultSet.getString("COLUMN_NAME");
                    columns.add(columnName);
                }
                tableColumns.put(table, columns);
                resultSet.close();
            } catch (SQLException e)
            {
                e.printStackTrace();
            }
        } else
        {
            columns = tableColumns.get(table);
        }
        return columns;
    }

    public static void init(Connection connection)
    {
        if (initialized == Boolean.FALSE)
        {
            synchronized (DBMetaObjectHolder.class)
            {
                if (initialized == Boolean.FALSE)
                {
                    try
                    {
                        if (connection != null)
                        {
                            ResultSet resultSet = connection.getMetaData().getTables(null, connection.getMetaData().getUserName(), "%", new String[]{"TABLE"});
                            while (resultSet.next())
                            {
                                String tableName = resultSet.getString("TABLE_NAME");
                                primaryKeys.put(tableName, retrievePrimaryKey(connection, tableName));
                                tableColumns.put(tableName, retrieveTableColumns(connection, tableName));
                            }
                            resultSet.close();
                            initialized = Boolean.TRUE;
                        }
                    } catch (SQLException e)
                    {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    static Map<String, String> getPrimaryKeys()
    {
        return primaryKeys;
    }

    static Map<String, List<String>> getTableColumns()
    {
        return tableColumns;
    }

    public static Boolean getInitialized()
    {
        return initialized;
    }
}
